﻿namespace Pp.Repository
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Reflection;
    using System.Security.Principal;
    using System.Web;
    using Core;
    using Core.Extentions;
    using Core.File;
    using Dto;
    using Globalization;
    using NHibernate;
    using NHibernate.Criterion;
    using Domain.Model;
    using NHibernate.Transform;

    public class UserRepository : BaseRepository<User>
    {
        public UserRepository(ISession session, HttpServerUtilityBase server)
            : base(session, server)
        {
        }
   
        public User GetByUsername(string username)
        {
            return Session.CreateCriteria<User>()
                .Add(Restrictions.Eq("Username", username))
                .Add(Restrictions.Eq("IsActive", true)).UniqueResult<User>();
        }
        public UserSmallDto GetByUserName(string username)
        {
            var user = GetByUsername(username);
            return user.ToSmallDto();
        }
        public T GetByUsername<T>(string username)
        {
            var user = Session.CreateCriteria<User>()
                .Add(Restrictions.Eq("Username", username))
                .Add(Restrictions.Eq("IsActive", true));
            var list = Projections.ProjectionList();
            foreach (var property in typeof(T).GetProperties()
                .Where(property => property.MemberType == MemberTypes.Property))
            {
                if (property.PropertyType != typeof(HttpPostedFileBase))
                {
                    list.Add(Projections.Property(property.Name), property.Name);
                }
            }
            user.SetProjection(list);
            return user.SetResultTransformer(new AliasToBeanResultTransformer(typeof(T))).UniqueResult<T>();
        }
        public User GetByMail(string mail)
        {
            return Session.CreateCriteria<User>()
                   .Add(Restrictions.Eq("MailAdress", mail))
                   .Add(Restrictions.Eq("IsActive", true)).UniqueResult<User>();
        }
        public bool IsExists(string username)
        {
            return GetByUsername(username) != null;
        }
        public bool IsExists(string username, string diffrentName)
        {
            var name = GetByUsername(username);
            return name != null && name.Username != diffrentName;
        }
        public bool IsExistsMail(string email)
        {
            return GetByMail(email) != null;
        }
        public bool IsExistsMail(string email, string diffrent)
        {
            var user = GetByMail(email);
            return user != null && user.MailAdress != email;
        }
        public bool ValidateUser(string userName, string password)
        {
            var user = GetByUsername(userName);
            if (user == null) return false;
            return user.Password == password;
        }
        public void CreateUser(string userName, string password, string email, out Result status)
        {
            if (IsExists(userName))
            {
                status = Result.AsError(Res.Error_UserName_Exist);
            }
            else if (IsExistsMail(email))
            {
                status = Result.AsError(Res.Error_UserMail_Exist);
            }
            else
            {
                var user = new User
                               {
                                   Password = password,
                                   Username = userName.ToSeo(),
                                   MailAdress = email,
                                   IsActive = true,
                               };
                Save(user);
                status = Result.AsSuccess();
            }
        }
        public Result ChangePassword(string userName, string oldPassword, string newPassword)
        {
            var user = GetByUsername(userName);
            if (user == null) return Result.AsError(Res.Information_User_nofound);
            if (user.Password != oldPassword) return Result.AsError(Res.Information_incorrect_password);
            if (user.OldPassword == newPassword || user.Password == newPassword) return Result.AsError(Res.Information_password_not_be_equal); ;
            user.Password = newPassword;
            user.OldPassword = oldPassword;
            Update(user);
            var message = CreateMail(Res.Label_PasswordEdit, MailType.PasswordChange, new List<MailModel>
                                                                                  {
                                                                                      new MailModel("OldPassword", oldPassword),
                                                                                      new MailModel("NewPassword", newPassword)
                                                                                  }, user.MailAdress).Data;
            SendMail(message);
            return Result.AsSuccess();
        }

        public Result UpdateProfile(UserEditDto userEditDto, string name)
        {
            var user = GetByUsername(name);
            if (IsExists(userEditDto.Username, user.Username)) return Result.AsError(Res.Information_User_allready_exsist);
            if (IsExistsMail(userEditDto.MailAdress, user.MailAdress)) return Result.AsError(Res.Information_mail_allready_exsist);

            user.CvInfo = userEditDto.CvInfo;
            user.FirstName = userEditDto.FirstName;
            user.LastName = userEditDto.LastName;
            user.MailAdress = userEditDto.MailAdress;
            user.Username = userEditDto.Username.ToSeo();
            user.WorkInfo = userEditDto.WorkInfo;
            user.EducationalInfo = userEditDto.EducationalInfo;
            user.BirthDay = userEditDto.BirthDay;
            user.IsMan = userEditDto.IsMan;
            user.City = userEditDto.City;
            user.MailAdressVisible = userEditDto.MailAdressVisible;
            Update(user);
            if (userEditDto.PictureFile != null)
            {
                var saveResult = SavePicture("/Content/Upload/Avatar/", userEditDto.PictureFile, ImageSize.smallSize, user.Id);
                if (!saveResult.Success) return Result.AsError(saveResult.Error);
                saveResult = SavePicture("/Content/Upload/Avatar/", userEditDto.PictureFile, ImageSize.mediumSize, user.Id);
                if (!saveResult.Success) return Result.AsError(saveResult.Error);
                saveResult = SavePicture("/Content/Upload/Avatar/", userEditDto.PictureFile, ImageSize.largeSize, user.Id);
                if (!saveResult.Success) return Result.AsError(saveResult.Error);
            }

            SendMail(CreateMail(Res.Label_ProfileEdit, MailType.ProfileUpdate, new List<MailModel> { new MailModel("FullName", user.GetFullName()) }, user.MailAdress).Data);
            return Result.AsSuccess();
        }

        public WallItem GetWallItem(string name, bool isMyProfile)
        {
            var user = GetByUsername(name);
            if (user == null) return new WallItem();
            var wallItem = new WallItem
                               {
                                   Detail = user.ToDto(),
                                   Projects = user.Projects.OrderByDescending(d=>d.CreateDate).Take(3).ToList().ToDto(),
                                   IsMyProfile = isMyProfile,
                                   MyLikes = user.MyLikes.ToDto(),
                                   TheyLikes = user.TheyLikes.ToDto()
                               };

            return wallItem;
        }

        public PageList<UserDto> GetUsers(int? page, int size)
        {
            var users = GetAll(page, size, "/Account/List").ToDto();
            return users;
        }

        public Result<int> Like(Guid? id, string name)
        {
            var processor = GetByUsername(name);//Beğenen kişiler
            var user = Get(id);//Beğenilen
            if (user == null || processor == null)
                return Result<int>.AsError(Res.Information_Object_NoFound);
            if (user.TheyLikes.Where(d => d.Processor.Username == name).Count() > 0)
                return Result<int>.AsError(Res.Information_like_allready_exsist_for_user);
            var like = new UserLike
                           {
                               Processor = processor,
                               User = user
                           };
            Session.Save(like);
            user.TheyLikes.Add(like);
            Update(user);
            var count = user.TheyLikes.Count;

            SendMail(CreateMail(Res.Information_Profile_like, MailType.ProfileLike, new List<MailModel>
                                  {
                                      new MailModel("FullName", user.Username),
                                      new MailModel("LikeCount", count.ToString()),
                                  }, user.MailAdress).Data);
            return Result<int>.AsSuccess(count);
        }
        public Result<int> Dislike(Guid? id, string name)
        {
            var user = Get(id);
            if (user == null)
                return Result<int>.AsError(Res.Information_Object_NoFound);
            var like = user.TheyLikes.Where(d => d.Processor.Username == name).SingleOrDefault();
            if (like == null)
                return Result<int>.AsError(Res.Information_liked_project);
            Session.Delete(like);
            user.TheyLikes.Remove(like);
            Update(user);
            var count = user.TheyLikes.Count;
            return Result<int>.AsSuccess(count);
        }

        public IList<string> GetNotifications(string name)
        {
            var list = new List<string>();
            var user = GetByUsername(name);
            if (user == null) return list;
            foreach (var like in user.TheyLikes.Where(d => d.IsShowed == false))
            {
                like.IsShowed = true;
                list.Add(like.ToDto().ToNotification(true, true));
                Session.Update(like);
            }
            foreach (var proj in user.Projects)
            {
                foreach (var like in proj.Likes.Where(d => d.IsShowed == false))
                {
                    like.IsShowed = true;
                    list.Add(like.ToDto().ToNotification(true, true));
                    Session.Update(like);
                }
                foreach (var like in proj.Comments.Where(d => d.IsShowed == false))
                {
                    like.IsShowed = true;
                    list.Add(like.ToDto().ToNotification(true, true));
                    Session.Update(like);
                }
                Session.Update(proj);
            }

            Update(user);
            return list;
        }

       
    }
}
